#include "async_function.hpp"

struct AsyncData {
    napi_deferred deferred;
    napi_async_work asyncWork;
    std::queue<std::string> value;
    std::queue<std::string> key;
    void *reserve;
    ~AsyncData()
    {
        LOGINFO("~AsyncData");
    }
};

void AsyncExecute(napi_env env, void *data)
{
    // 一般做一些耗时操作，该函数不能进行napi_value相关操作,数据通过data转移到complete函数进行napi_value相关处理
}

void AsyncComplete(napi_env env, napi_status status, void *data)
{
//     napi_handle_scope scope;
//     napi_open_handle_scope(env, &scope);

    struct AsyncData *asyncData = (struct AsyncData *)data;
    napi_value object;
    status = napi_create_object(env, &object);
    STATUS_CHECK(status);
    
    while(!asyncData->key.empty()) {
        napi_value key, value;
        status = napi_create_string_utf8(env, asyncData->key.front().c_str(), NAPI_AUTO_LENGTH, &key); // key必须是字符串类型
        STATUS_CHECK(status);

        status = napi_create_string_utf8(env, asyncData->value.front().c_str(), NAPI_AUTO_LENGTH, &value); // value可以是任意其他类型，不一定是字符串
        STATUS_CHECK(status);

        status = napi_set_property(env, object, key, value);
        STATUS_CHECK(status);
        
        asyncData->key.pop();
        asyncData->value.pop();
    }

    napi_value key, value;
    status = napi_create_string_utf8(env, "key100", NAPI_AUTO_LENGTH, &key); // key必须是字符串类型
    STATUS_CHECK(status);

    status = napi_create_string_utf8(env, "value100", NAPI_AUTO_LENGTH, &value); // value可以是任意其他类型，不一定是字符串
    STATUS_CHECK(status);

    status = napi_set_property(env, object, key, value);
    STATUS_CHECK(status);

    napi_resolve_deferred(env, asyncData->deferred, object);
    // napi_reject_deferred(env, asyncData->deferred, asyncData->data); //返回给异常函数
    napi_delete_async_work(env, asyncData->asyncWork);
    delete asyncData;
//     napi_open_handle_scope(env, &scope);
}




// JS层object类型转化成C++ 类型  promise
napi_value demo_async_function::AsyncPassingObjectReturnObject(napi_env env, napi_callback_info info){
    size_t argc = 1;
    napi_value argv[1] = {nullptr};
    napi_status status;
    napi_value promise;
    struct AsyncData *asyncData = new AsyncData;

    status = napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
    STATUS_CHECK(status);

    // 打印object中的数据
    napi_value nameArray;
    status = napi_get_property_names(env, argv[0], &nameArray); // 获取obj属性的name list
    STATUS_CHECK(status);

    uint32_t length = 0;
    status = napi_get_array_length(env, nameArray, &length); // 获取list 长度
    STATUS_CHECK(status);
    
    char key1[BUFF_SIZE] = {0};
    char value1[BUFF_SIZE] = {0};
    
    for (int i = 0; i < length; i++) {
        napi_value key;
        status = napi_get_element(env, nameArray, i, &key); // 遍历list，获取每个元素的key
        STATUS_CHECK(status);
        
        size_t len = 0;
        status = napi_get_value_string_utf8(env, key, key1, BUFF_SIZE, &len);
        STATUS_CHECK(status);
        asyncData->key.push(key1);

        napi_value value;
        status = napi_get_property(env, argv[0], key, &value); // 通过key获取value
        STATUS_CHECK(status);

        size_t vlen = 0;
        status = napi_get_value_string_utf8(env, value, value1, BUFF_SIZE, &vlen);
        STATUS_CHECK(status);
        asyncData->value.push(value1);
    }
    
    status = napi_create_promise(env, &asyncData->deferred, &promise);
    STATUS_CHECK(status);
    
    napi_value asyncWorkName;
    status = napi_create_string_utf8(env, "AsyncPassingObjectReturnObject", NAPI_AUTO_LENGTH, &asyncWorkName);
    STATUS_CHECK(status);
    
    status = napi_create_async_work(env, nullptr, asyncWorkName, AsyncExecute, AsyncComplete, asyncData, &asyncData->asyncWork);
    STATUS_CHECK(status);
    
    // status = napi_queue_async_work(env, asyncData->asyncWork);
    status = napi_queue_async_work_with_qos(env, asyncData->asyncWork, napi_qos_default);
    STATUS_CHECK(status);
    
    return promise;
}

napi_value demo_async_function::Exports(napi_env env, napi_value &exports)
{
    napi_property_descriptor desc[] = {
        {"AsyncPassingObjectReturnObject", nullptr, demo_async_function::AsyncPassingObjectReturnObject, nullptr, nullptr, nullptr, napi_default, nullptr}
    };
    
    napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
    return exports;
}

 